﻿using FreeSql;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Sage.FreeSqlManager.Core;
using Sage.FreeSqlManager.Models;
using System.Reflection;


namespace Sage.FreeSqlManager.Extensions
{
    /// <summary>
    /// 服务集合扩展方法 - 提供FreeSql相关服务注册
    /// </summary>
    public static class ServiceExtensions
    {
        #region 单库模式 - 直接使用IFreeSql

        /// <summary>
        /// 添加单个FreeSql实例 - 从配置中读取指定数据库
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configuration">配置</param>
        /// <param name="dbName">数据库名称，对应配置中的键名</param>
        /// <param name="sectionName">配置节名称，默认为"DbConnections"</param>
        /// <returns>服务集合</returns>
        /// <exception cref="InvalidOperationException">配置错误时抛出</exception>
        public static IServiceCollection AddFreeSql(
            this IServiceCollection services,
            IConfiguration configuration,
            string dbName,
            string sectionName = "DbConnections")
        {
            // 1. 从配置中获取数据库配置
            var dbConfig = FreeSqlHelper.GetDbConfig(configuration, dbName, sectionName);

            // 2. 创建FreeSql实例
            var fsql = FreeSqlHelper.CreateFreeSqlInstance(dbConfig, dbName);

            // 3. 注册IFreeSql为单例
            services.AddSingleton(_ => fsql);

            Console.WriteLine("已注册IFreeSql普通单例服务");

            return services;
        }

        /// <summary>
        /// 添加单个FreeSql实例 - 直接指定参数
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="dataType">数据库类型</param>
        /// <param name="connectionString">连接字符串</param>
        /// <param name="configAction">可选的配置动作</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddFreeSql(
            this IServiceCollection services,
            DataType dataType,
            string connectionString,
            Action<DbConnectionConfig>? configAction = null)
        {
            // 1. 创建基础配置对象
            var config = new DbConnectionConfig
            {
                ConnectionString = connectionString,
                DataType = dataType
            };

            // 2. 应用额外配置
            configAction?.Invoke(config);

            // 3. 创建FreeSql实例
            var fsql = FreeSqlHelper.CreateFreeSqlInstance(config, "default");

            // 4. 注册IFreeSql为单例
            services.AddSingleton(_ => fsql);

            Console.WriteLine("已注册IFreeSql普通单例服务");

            return services;
        }

        /// <summary>
        /// 添加单个FreeSql实例并配置事务支持 - 从配置中读取
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configuration">配置</param>
        /// <param name="dbName">数据库名称，对应配置中的键名</param>
        /// <param name="sectionName">配置节名称，默认为"DbConnections"</param>
        /// <param name="addRepository">是否自动添加仓储支持</param>
        /// <returns>服务集合</returns>
        /// <remarks>
        /// 此方法会注册事务感知的IFreeSql实例，使注入IFreeSql的服务自动获得事务支持
        /// </remarks>
        public static IServiceCollection AddFreeSqlWithTransaction(
            this IServiceCollection services,
            IConfiguration configuration,
            string dbName,
            string sectionName = "DbConnections",
            bool addRepository = true)
        {
            // 1. 从配置中获取数据库配置
            var dbConfig = FreeSqlHelper.GetDbConfig(configuration, dbName, sectionName);

            // 2. 创建FreeSql实例(不立即注册)
            var fsql = FreeSqlHelper.CreateFreeSqlInstance(dbConfig, dbName);

            // 3. 注册UnitOfWorkManager(使用外部创建的fsql实例)
            services.AddScoped(_ => new UnitOfWorkManager(fsql));

            // 4. 注册作用域的IFreeSql(跟随UnitOfWorkManager切换)
            services.AddScoped(r => r.GetService<UnitOfWorkManager>()?.Orm ??
                throw new InvalidOperationException("无法获取UnitOfWorkManager.Orm"));

            // 6. 添加仓储支持
            if (addRepository)
            {
                services.AddFreeSqlRepositories();
            }

            Console.WriteLine("已注册IFreeSql事务模式服务");
            return services;
        }

        /// <summary>
        /// 添加单个FreeSql实例并配置事务支持 - 直接指定参数
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="dataType">数据库类型</param>
        /// <param name="connectionString">连接字符串</param>
        /// <param name="configAction">可选的配置动作</param>
        /// <param name="addRepository">是否自动添加仓储支持</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddFreeSqlWithTransaction(
            this IServiceCollection services,
            DataType dataType,
            string connectionString,
            Action<DbConnectionConfig>? configAction = null,
            bool addRepository = true)
        {
            // 1. 创建基础配置对象
            var config = new DbConnectionConfig
            {
                ConnectionString = connectionString,
                DataType = dataType
            };

            // 2. 应用额外配置
            configAction?.Invoke(config);

            // 3. 创建FreeSql实例(不立即注册)
            var fsql = FreeSqlHelper.CreateFreeSqlInstance(config, "default");

            // 4. 注册UnitOfWorkManager(使用外部创建的fsql实例)
            services.AddScoped(_ => new UnitOfWorkManager(fsql));

            // 5. 注册作用域的IFreeSql(跟随UnitOfWorkManager切换)
            services.AddScoped(r => r.GetService<UnitOfWorkManager>()?.Orm ??
                throw new InvalidOperationException("无法获取UnitOfWorkManager.Orm"));

            //// 6. 可选：注册单例IFreeSql(非事务版本，用于特殊场景)，如果使用统一事务，这里没啥用了。
            //services.AddSingleton<IFreeSql>(_ => fsql);

            // 7. 添加仓储支持
            if (addRepository)
            {
                services.AddFreeSqlRepositories();
            }

            Console.WriteLine("已注册IFreeSql事务模式服务");

            return services;
        }

        /// <summary>
        /// 添加单个FreeSql实例并配置事务支持 - 直接指定参数
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configAction">配置动作</param>
        /// <param name="addRepository">是否自动添加仓储支持</param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="InvalidOperationException"></exception>
        public static IServiceCollection AddFreeSqlWithTransaction(
            this IServiceCollection services,
            Action<DbConnectionConfig>? configAction = null,
            bool addRepository = true)
        {
            // 1. 创建配置对象（用默认值）
            var config = new DbConnectionConfig();

            // 2. 应用外部自定义配置
            configAction?.Invoke(config);

            // 3. 校验必填项
            if (string.IsNullOrWhiteSpace(config.ConnectionString))
                throw new ArgumentException("ConnectionString 必须设置", nameof(configAction));
            // DataType 如果有默认值（如 MySql），可不校验，否则加校验
            // if (config.DataType == null) throw new ArgumentException("DataType 必须设置", nameof(config));

            // 4. 创建 FreeSql 实例
            var fsql = FreeSqlHelper.CreateFreeSqlInstance(config, "default");

            // 5. 注册 UnitOfWorkManager
            services.AddScoped(_ => new UnitOfWorkManager(fsql));

            // 6. 注册 IFreeSql
            services.AddScoped(r => r.GetService<UnitOfWorkManager>()?.Orm
                ?? throw new InvalidOperationException("无法获取UnitOfWorkManager.Orm"));

            // 7. 添加仓储支持
            if (addRepository)
                services.AddFreeSqlRepositories();

            Console.WriteLine("已注册IFreeSql事务模式服务");

            return services;
        }

        #endregion

        #region 多库模式 - 使用工厂

        /// <summary>
        /// 添加FreeSql工厂 - 从配置中读取
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="sectionName">配置节名称，默认为"DbConnections"</param>
        /// <param name="addRepository">是否自动添加仓储支持</param>
        /// <returns>服务集合</returns>
        /// <remarks>
        /// 此方法注册IFreeSqlFactory，用于多数据库场景，通过名称获取不同的数据库连接。
        /// 注意：多库模式下不支持自动的跨库事务，每个数据库的事务需要单独管理。
        /// </remarks>
        public static IServiceCollection AddFreeSqlFactory(
            this IServiceCollection services,
            string sectionName = "DbConnections",
            bool addRepository = true)
        {
            // 注册IFreeSqlFactory为单例
            services.AddSingleton<IFreeSqlFactory>(provider =>
                new FreeSqlFactory(provider, sectionName));

            // 添加仓储支持
            if (addRepository)
            {
                services.AddFreeSqlRepositories();
            }
            Console.WriteLine("已注册IFreeSql工厂模式服务");
            return services;
        }

        #endregion

        /// <summary>
        /// 添加FreeSql仓储支持
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="assemblies">包含实体的程序集，如果为空则只注册基本仓储</param>
        /// <returns>服务集合</returns>
        /// <remarks>
        /// 如果提供程序集参数，将扫描指定程序集中的实体并为它们注册仓储
        /// </remarks>
        public static IServiceCollection AddFreeSqlRepositories(
            this IServiceCollection services,
            params Assembly[] assemblies)
        {
            // 使用FreeSql原生方法注册仓储
            if (assemblies is { Length: > 0 })
            {
                foreach (var assembly in assemblies)
                {
                    // 直接调用FreeSql的AddFreeRepository方法
                    // 编译器会自动查找正确的命名空间
                    services.AddFreeRepository(assembly);
                }
            }
            else
            {
                // 无程序集参数时注册基本仓储
                services.AddFreeRepository();
            }
            Console.WriteLine("已注册IFreeSql仓库服务");
            return services;
        }

    }
}